// 作用：webpack打包的入口的文件
import Vue from "vue"; // 导入Vue构造函数
import "normalize.css/normalize.css"; // 导入第三方重置样式模块
import ElementUI from "element-ui"; // 导入ElementUI组件（一次性导入）
import "element-ui/lib/theme-chalk/index.css";

import elementEN from "element-ui/lib/locale/lang/en"; // 导入ElementUI英文的语言包
import elementZH from "element-ui/lib/locale/lang/zh-CN"; //导入ElementUI中文的语言包
import customEN from "./lang/en"; //导入自己写的的英文语言包
import customZH from "./lang/zh"; //导入自己写的的中文语言包

import "@/styles/index.scss"; // 导入自己的样式文件
import App from "./App"; //导入项目根组件
import store from "./store"; //导入store实例
import router from "./router"; //导入router实例
import "@/icons"; // 导入字体图标
import "@/permission"; // 导入权限控制文件
import "@/ditective"; //导入自定义指令模块
import Print from "vue-print-nb"; //导入打印指定的内容
import PageHeader from "@/components/PageHeader"; // 导入全局组件
import UploadExcel from "@/components/UploadExcel"; //导入全局组件
import UploadImg from "@/components/UploadImg"; //导入全局组件
import ScreenFull from "@/components/ScreenFull"; //导入全局组件
import ThemePicker from "@/components/ThemePicker"; //导入全局组件
import Lang from "@/components/Lang"; //导入全局组件
import TagsView from "@/components/TagsView"; //导入全局组件
Vue.component(ScreenFull.name, ScreenFull); // 注册全屏组件
Vue.component(ThemePicker.name, ThemePicker); // 注册全屏组件

Vue.component(PageHeader.name, PageHeader); // 注册全局组件
Vue.component(UploadExcel.name, UploadExcel); // 注册全局组件
Vue.component(UploadImg.name, UploadImg); //注册全局组件
Vue.component(Lang.name, Lang); //注册全局组件
Vue.component(TagsView.name, TagsView); //注册全局组件
//这个是按钮权限控制用原型链，我们在此定义以后就不用在每个标签
//上给每一个定义了，要是使用v-if="$cheackPermission('与后台确定的值')
Vue.prototype.$cheackPermission = function (key) {
  //拿到vuex中points数组（导入store）
  const { points } = store.state.user.userInfo.roles;
  // 判断当前传入的权限点在不在points;
  return points.includes(key);
};

// Vue.use(ElementUI, { locale }); //注册ElementUI的全部组件，并提供英文语言模式
// 如果想要中文版 element-ui，按如下方式声明
Vue.use(ElementUI);
Vue.use(Print); //注册 ->提供全局的v-print指令
Vue.config.productionTip = false; //关闭控制台提示
// 多语言切换(国际化)
// 1.下包: yarn add vue-i18n@8 -S
import VueI18n from "vue-i18n"; //默认导入// 2.引入
Vue.use(VueI18n); //注册// 3.注册
// 4定义翻译规则 = ElementUI+自己的
const messages = {
  //英文
  en: {
    //对象展开到新对象中
    ...elementEN,
    ...customEN,
  },
  //中文
  zh: {
    //对象展开到新对象中
    ...elementZH,
    ...customZH,
  },
};
import Cookies from "js-cookie";
// 5，创建i18n实例
const i18n = new VueI18n({
  // 刷新页面的时候取出Cookie的值，如果没有就往后走
  locale: Cookies.get("language") || "zh", //默认的语言，zh表示中文,en表示英文
  messages, //翻译的规则
});

//实例化vm实例
// new Vue({
//   el: "#app",
//   router,
//   store,
//   render: (h) => h(App),
// });
// 实例化vm实例;
new Vue({
  // 注入 router 实例
  router,
  // 注入 store 实例
  store,
  // 6.注入
  //注入i18n实例
  i18n, //提供 全局的 $t 方法，进行语言的翻译
  // 染函数，把根组件App的内容渲染到id=app的盒子位置
  // id=app盒子在public/index.html文件中
  render: (h) => h(App),
}).$mount("#app");

// 页面/路由的访问权的核心实现思路:
//  1.主页的左侧菜单是基于路由表动态生成的(控制左侧菜单的不同只需要控制路由表即可)
//  2.路由表划分为静态路由表和动态路由表，控制权限的不同就是在控制动态路由表
//  3.在路由全局全局守卫中，基于请求到的用户菜单，对动态路由表做筛选(比对路由规则的名字是否在用户菜单数组中)
//  4.把筛选的结果通过路由实例的addRoute方法动态追加到路由表中(输入path可以看到component)
//  5.vuex管理一份路由表，同步相应菜单的显示(因为router.options.routes不是响应式的)

//按钮的操作权，3种实现方式

// (1)3种实现方式:
// 1.是否渲染(v-if指令)
// 2.是否禁用(: disabled属性)
// 3.代码中的逻辑判断(有权限放行，否则直接return)
// (2) 代码中
// 1.自定义全局指令(v-permission)
// 判断指令绑定表达式的值是否在vuex中的用户权限点的数组中
// 2.给Vue新增原型方法($checkPermission)
// 判断方法参数值是否在vuex中用户权限点的数组中

// const messages = {
//   //中文测试
//   // zh: {
//   //   App: {
//   //     hi: "姬霓太美",
//   //     msg: "下午好",
//   //   },
//   // },
//   //英文测试
//   // cn: {
//   //   App: {
//   //     hi: "Ji Ni is too beautiful",
//   //     msg: "Good afternoon",
//   //   },
//   // },
// };

// nvm切换node版本：
// 1. 全局安装nvm: npm i nvm -g
// 2. 查看所有node版本: nvm ls
// 3. 切换node版本: nvm use 指定node版本号
// 4. 查看node版本: node -v

// 什么是虚拟DOM为啥用虚拟DOM？
// 1. 概念: 保存了DOM元素关键信息的一个JS对象
// 2. 好处: 大大减少比对的次数、大大提高DOM更新的速度

// 什么diff算法及有啥用diff算法？
// 1. 概念: 找不同算法
// 2. diff算法: 在Vue中当数据变了，比对数据变化前后两份虚拟DOM的差异，
//              找到虚拟DOM变化的地方，然后把对应的差异映射到真实DOM

// 闭包的概念优缺点：
// 概念：两个函数嵌套，内函数用到了外函数的变量，
//      导致外函数的变量不会被释放，延长了外函数变量的生命周期
// 优点：让变量私有化(局部变量)，对外提供访问方法
// 缺点/特点：内存泄露

// RBAC页面/路由的访问权的核心实现思路：
// RBAC: 基于角色的权限控制，核心思想是给员工分配角色，给角色分配权限，
//       实现不用员工登录成功看到的左侧菜单不同(权限不同)
// 1. 主页的左侧菜单是基于路由表动态生成的(控制左侧菜单的不同只需要控制路由表即可)
// 2. 路由表划分为静态路由表和动态路由表，控制权限的不同就是在控制动态路由表
// 3. 在路由全局全局守卫中，基于请求到的用户菜单，对动态路由表做筛选(比对路由规则的名字是否在用户菜单数组中)
// 4. 把筛选的结果通过路由实例的addRoute方法动态追加到路由表中(浏览器输入path可以看到component)
// 5. vuex管理一份路由表，同步相应菜单的显示(因为router.options.routes不是响应式的)

// 按钮的操作权：
// （1）3种实现方式：
//      1. 是否渲染(v-if指令)
//      2. 是否禁用(: disabled属性)
//      3. 代码中的逻辑判断(有权限放行, 否则直接return)
// (2) 代码中
//   1. 自定义全局指令(v-permission)
//        判断指令绑定表达式的值是否在vuex中用户权限点的数组中
//   2. 给Vue新增原型方法($checkPermission)
//        判断方法参数值是否在vuex中用户权限点的数组中

// 人资项目必会面试题：
// 1. token为什么用vuex和本地存储共同管理？(只用本地存储管理行不行)
// 答：2者都有优缺点
//    vuex:
//       优点：1. 响应式  2. 读写速度快(从内存中读写)    缺点：刷新会丢失（数据不会持久化）
//    本地存储/Cookie:
//       优点：刷新不丢失（数据会持久化）    缺点：1. 非响应式  2. 读取速度慢(从磁盘中读写)

// 2. token拦截/登录拦截/路由访问权限 如何实现？
// 答：1. 借助router.beforeEach((to, from, next) => { })路由全局前置守卫，
//        因为任何路由在被访问到之前必须经过回调函数的处理
//    2. 在回调中获取vuex中的token，判断token是否存在
//    3. 如果存在，直接放行
//    3. 否则，进一步判断要去的路由路径是否在白名单数组中，如果在，放行；否则跳转至登录，携带回跳地址

// 3. token过期了有哪些处理方案？
// 答：1. 在项目做过2中方式的token过期处理，分别是无感知的处理和有感知的处理
//    2. 无感知的处理也可以称为token的续签，在首次登录成功之后，后台会给到2个token信息，
//       一个叫token，另一个叫refreshToken，并且refreshToken的有效期比token长，当token过期了，
//       并不代表refreshToken也过期了，这个时候可以在响应拦截器中监测401状态码，用refreshToken请求
//       得到新token，然后把新token同步到vuex中，然后继续刚刚失败的请求
//    3. 有感知的处理就是2个token都过期了，清空token和用户信息，然后重新登陆；
//       或者在首次登录成功后台就只给了一个token，token过期了，同样的在响应拦截器中监测401状态码，然后重新登陆

// 4. 数据转换？
// 答：
//    1. 数组转树：
//       （1）在组织架构模块，后台给到的是列表(数组)数据，需要转换成树形结构，通过层级关系来渲染
//       （2）核心转换思路：
//             （1）自定义转换函数，首先查找一级部门，把找到的一级部门存入结果数组
//             （2）查找一级部门下是否存在子级部门，查找到的条件就是哪个部门的pid与当期那部门的id全等
//                 通过函数递归，得到子级部门，把得到子级children数组添加给一级部门的children属性

//    2. Excel的上传与下载
//     上传：
//        本质：把Excel文件中数据读到内存中，得到一个对象数组，
//        问题：但是每个对象中的键是中文的，需要转换成英文键，提交给后台
//        转换的核心思路：
//         1. 基于数组的map，自定义中英文键的映射关系对象，
//         2. 遍历对象，通过英文键得到中文键，再赋值给新对象即可
//     下载：
//        本质：把内存中对象数组写入Excel文件的过程
//        问题：后台给到的对象数组，写入到Excel中文中的数据是个二维数组
//        转换的核心思路：
//         1. 基于数组的map，自定义中英文键的映射关系对象，
//         2. 遍历表头数组，通过英文键得到中文键，再加入到新数组中

// 4. 项目中封装过哪些组件？封装组件的核心思路？
// 封装过哪些组件：封装过图片上传组件、页头组件、全屏组件等
// 核心思路(高内聚低耦合)：大致关注4个点
//  高内聚：组件内部把某个点的功能涵盖的很全面(功能强大)
//  低耦合：尽量保持组件的独立性(尽量不依赖其它组件，能够独立工作)
// 1. props: 父传子，使用组件的时候，通过自定义属性控制组件的外观/行为
// 2. slot: 插槽, 使用组件的时候，允许自定义标签结构分发内容
// 3. events: 事件，通过动作记录组件的行为
// 4. methods: 组件的方法
